package fundation;

/**
 * volatile：通过内存屏障实现单线程有序性（防止编译时指令重排和运行时使用屏障）和可见性
 * 详细解释参考：tip:os/程序运行过程.md-> 内存屏障

 * synchronized：原子性，可见性，有序（值多线程之间的有序，非指令重排），需要内核态与用户态切换，性能损耗大。
 *
 *
 */
public class VolatileDemo {

    public static void main(String[] args) {
        Runnable runnable = () -> Singleton.getSingleton().call();
         new Thread(runnable).start();
         new Thread(runnable).start();
         new Thread(runnable).start();
         new Thread(runnable).start();
         new Thread(runnable).start();
    }
}

/**
 * 此种单例方法可能会出现空指针异常。实际测试未出现该问题。
 * 参考 http://ifeve.com/doublecheckedlocking/ 此链接中提供的方法也未出现问题。
 *
 */
class Singleton {
    private static Singleton singleton;


    private Singleton() {
    }

    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();//并不是原子操作
/*此操作实际过程为
memory = allocate();   //1：分配对象的内存空间
ctorInstance(memory);  //2：初始化对象
instance = memory;     //3：设置 instance 指向刚分配的内存地址
此时可能会发生重排序，导致第二步和第三步发生重排序，从而使得其他线程的第一个if (singleton == null)判断为否，直接获取到未初始化完成的对象，导致调用该对象中的某些方法时出现空指针异常，解决方案使用volatile修饰singleton。
*/
                }
            }
        }
        return singleton;
    }

    public void call() {
        System.out.println("可能会出现空指针异常");
    }
}